/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package cn.ac.iie.di.ban.ycl.wx.audio.server.handler;

import cn.ac.iie.di.ban.ycl.wx.audio.server.common.RuntimeEnv;
import static cn.ac.iie.di.ban.ycl.wx.audio.server.common.RuntimeEnv.requestDir;
import static cn.ac.iie.di.ban.ycl.wx.audio.server.common.RuntimeEnv.requestQueue;
import cn.ac.iie.di.ban.ycl.wx.audio.server.main.AudioServer;
import cn.ac.iie.di.ban.ycl.wx.audio.server.utils.FileTools;
import cn.ac.iie.di.ban.ycl.wx.audio.server.utils.MD5util;
import cn.ac.iie.di.ban.ycl.wx.audio.server.utils.Suffixutil;
import cn.ac.iie.di.ban.ycl.wx.audio.server.utils.CurrentTimeutil;
import cn.ac.iie.di.commons.httpserver.framework.handler.HandlerI;
import cn.ac.iie.di.commons.httpserver.framework.util.ParseRequestStream;
import com.alibaba.fastjson.JSONObject;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.eclipse.jetty.server.Request;

/**
 *
 * @author Administrator
 */
public class AudioHandler implements HandlerI {
    
    static Logger logger = Logger.getLogger(AudioHandler.class.getName());
    
    @Override
    public void init() throws Exception {
    }
    
    @Override
    public void execute(Request arg0, HttpServletRequest arg1, HttpServletResponse arg2) throws Exception {
        ServletOutputStream out = arg2.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(out);
        String responseFileName = null;
        long reqtime = CurrentTimeutil.currentTime();//能保持唯一性？
//        long reqtime = CurrentTimeutil.currentTime();//能保持唯一性？
        try {
            
            String audioReq = ParseRequestStream.parseRequestStreamAsString(arg0.getInputStream());
            logger.info(reqtime + " receive request : " + audioReq);
            String url_md5 = "";
            String reponseCode = "";//错误返回码
            InputStream inputStream = null;//返回流
            //解析json获取url，md5获取文件名
            if (RuntimeEnv.wxAudioUrlQueryLimit.get() < Integer.parseInt((String) RuntimeEnv.getParam(RuntimeEnv.WXAUDIOLIMIT))) {
                RuntimeEnv.wxAudioUrlQueryLimit.incrementAndGet();
                
                try {
                    JSONObject reqJson = JSONObject.parseObject(audioReq);
                    String pushtime = reqJson.getString("pt");
                    String url = reqJson.getString("url");
                    if (url == null || url.equals("")) {
                        logger.warn(reqtime + "request url is null");
                    } else {
                        url_md5 = MD5util.string2MD5(url);
                        //获取文件后缀,有待弄

                        String audio_suffix = Suffixutil.suffix(url);
                        if (audio_suffix == null) {
                            logger.warn(reqtime + "audio_suffix = " + audio_suffix + ",no such type audio,named default .mp3");
                            audio_suffix=".mp3";
//                            reponseCode = "{\"code\":-5,\"errorinfo\":\"网闸未返回文件，请稍候重试\"}";
//                            logger.info(reqtime+reponseCode);
                        }
                        //龙存存在该文件
                        if (pushtime == null || pushtime.equals("")) {
                            pushtime = Long.toString(reqtime);
                        }
                        String delay = reqJson.getString("delay");
                        if (delay == null || delay.equals("")) {
                            delay = "3";
                        }
                        //获取文件
                        //先轮询龙存是否存在该文件
                        String loongFileName = (String) RuntimeEnv.getParam(RuntimeEnv.loongstore) + url_md5 + audio_suffix;
                        File file = new File(loongFileName);
                        
                        if (file.exists()) {
                            //直接返回该文件
                            logger.info(reqtime + " loongstore fileName = " + loongFileName);
                            inputStream = new FileInputStream(file);
                            logger.info(reqtime + "get audio success !");
                        } else {
                            //拼接json,参数？
                            String json = "{\"url\":\"" + url + "\",\"pt\":\"" + pushtime + "\",\"delay\":\"" + delay + "\",\"url_md5\":\"" + url_md5 + "\"}";
                            //json放到map中写json文件到互联网去进行下载
                            //去重？，写完测试再看看要不要去重
                            while (true) {
                                if (requestQueue.offer(json)) {
                                    break;
                                }
                                try {
                                    Thread.sleep(10);
                                } catch (Exception e) {
                                    logger.error(reqtime + e.getMessage(), e);
                                }
                                
                            }
                            //在规定的时间内轮询网闸传递过来的文件夹
                            long endtime = System.currentTimeMillis();
                            boolean responseFlag = false;
                            int delayInt = Integer.parseInt(delay);
                            while ((endtime - reqtime) <= delayInt * 60*1000) {
                                //轮询一张表获取该文件夹下信息
                                if (RuntimeEnv.responseMap.containsKey(url_md5)) {
                                    responseFlag = true;
                                    break;
                                }
                                try {
                                    Thread.sleep(100);
                                } catch (Exception e) {
                                    logger.error(reqtime + e.getMessage(), e);
                                };
                                endtime = System.currentTimeMillis();
                            }
                            logger.info(reqtime + " get responseMap use(ms) : " + (endtime - reqtime));
                            if (responseFlag) {
                                //从互联网区接收文件回来
                                //发送正确文件并挪文件到龙存，移除responseMap信息
                                String responseurl_md5 = RuntimeEnv.responseMap.get(url_md5);
                                responseFileName = (String) RuntimeEnv.getParam(RuntimeEnv.responseDir) + RuntimeEnv.responseMap.get(url_md5);
                                if (responseurl_md5.equals("") || responseurl_md5 == null) {
                                    //尝试去龙存获取该文件
                                    responseFileName = (String) RuntimeEnv.getParam(RuntimeEnv.loongstore) + url_md5 + "." + audio_suffix;
                                }
                                
                                if (responseFileName.endsWith(".json")) {
                                    //解析json文件获取失败原因，主要有以下两种
                                    File errorfile = new File(responseFileName);
                                    FileReader reader = new FileReader(errorfile);
                                    BufferedReader br = new BufferedReader(reader);
                                    String errorjson = "";
                                    while ((errorjson = br.readLine()) != null) {
                                        reponseCode = errorjson;
//                                    reponseCode = "{\"code\":-6,\"errorinfo\":\"音频下载超出预定等待时间，请稍候重试\"}";
//                                    reponseCode = "{\"code\":-7,\"errorinfo\":\"音频文件下载失败，互联网区返回400\"}";
                                    }//说明互联网区下载失败
//                                    logger.info(reqtime + "error reponseCode = " + reponseCode);
                                } else {
                                    //正确的到文件

                                    File corrrectfile = new File(responseFileName);
                                    if (corrrectfile.exists()) {
                                        inputStream = new FileInputStream(corrrectfile);
                                        logger.info(reqtime + "get audio success !");
                                    } else {
//                                        logger.warn(reqtime + " can not find file " + responseFileName);
                                        reponseCode = "{\"code\":-5,\"errorinfo\":\"网闸未返回文件，请稍候重试\"}";
                                    logger.info(reqtime+reponseCode);
                                    }
                                }
                            } else {
                                //返回
                                reponseCode = "{\"code\":-5,\"errorinfo\":\"网闸未返回文件，请稍候重试\"}";
                            logger.info(reqtime+reponseCode);
                            }
                            //移除并挪文件到龙存
                            //判断其他线程已经完成文件读取，移除时机
                            RuntimeEnv.responseMap.remove(url_md5, RuntimeEnv.responseMap.get(url_md5));
//                            new FileTools().moveFileToNewPath(file.getName(), requestDir);
                        }
                    }
                    
                } catch (NumberFormatException | IOException e) {
                    reponseCode = "{\"code\":-5,\"errorinfo\":\"网闸未返回文件，请稍候重试\"}";
                    logger.error(reqtime + "request is not a json,reutrn..." + e.getMessage(), e);
                }
            } else {
                reponseCode = "{\"code\":-4,\"errorinfo\":\"查询访问量超出最大并发，请稍候重试\"}";
            }
            if (reponseCode.length() > 0 || inputStream == null) {
                logger.warn(reqtime + "get audio fail because " + reponseCode);
                inputStream = new ByteArrayInputStream(reponseCode.getBytes("UTF-8"));
            }
            byte[] bytesContent = new byte[1024 * 2];
            int bytesReadIn = 0;
            
            while ((bytesReadIn = inputStream.read(bytesContent, 0, 1024 * 2)) > 0) {
                bos.write(bytesContent, 0, bytesReadIn);
            }
            bos.flush();
        } catch (Exception e) {
            logger.error(reqtime + e.getMessage(), e);
        } finally {
            bos.close();
            RuntimeEnv.wxAudioUrlQueryLimit.decrementAndGet();
            try {
                if (responseFileName != null) {
                    File file = new File(responseFileName);
                    FileUtils.copyFileToDirectory(file, new File((String) RuntimeEnv.getParam(RuntimeEnv.loongstore)), true);
                    logger.info(reqtime + "delete file " + file.delete() + ",use total time ms " + (System.currentTimeMillis() - reqtime));
                }
            } catch (Exception e) {
                logger.error(reqtime + e.getMessage(), e);
            }

//            new FileTools().moveFileToNewPath(responseFileName, requestDir);
        }
    }
    
}
